/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ai.backbropPlus;

import ai.*;
import ai.io.DataSource.Data;
import java.awt.Dimension;
import java.util.Arrays;
import java.util.Vector;
import uk.ac.bath.util.Tweakable;

/**
 *
 * @author pjl
 */

public class BackPropPlusBrain  extends AbstractBrain {
    
//    ImageLabel reality=null;
//    Vector<Image> imagination=new Vector<Image>();
    private int n;
   // float accel=0.1f;
    BackPropPlusF bp;
    int layerSizes[];
       
   // static int nLabels=10;
  
  //  private ImageLabel fantasy;
    
    private float[] in;
 //   Data out;
  //  private int nImage;
//    private int nLabel;
//   private Result result;
//    
    public BackPropPlusBrain(Dimension d,Dimension d2) {  
        super(d,d2,"Back Propagation Plus");
     //   this.nImage=d.height*d.width;
      //  this.nLabel=d2.height*d2.width;
        this.n=nPixel+nLabel;
        int nHidden=80;  //80
  //      int extra=30;
        int nMiddle=10;  // 20
     
        double beta=.001;
        double alpha=20;
    
        result=new Result(d,d2);

        in=new float[n];
        
        layerSizes=new int[]{n,nHidden,nMiddle,nHidden,n};
        
         // Creating the net
        bp = new BackPropPlusF(layerSizes, beta, alpha);

        
        for(int i=0;i<nHidden;i++) {
            imagination.add(new WeightVectorImage(bp.weight[1][i],d,"pre"+1));
        }
        // must pack image first into in array.
//
//        reality=new ImageLabel(new FloatVectorImage(bp.input(),d,"Reality"),-1);
//        fantasy=new ImageLabel(new FloatVectorImage(bp.output(),d,"Fantasy"),-1);

    }
//
//    public int getImaginationCount() {
//        return layerSizes[1];
//    }
//    
//    public Image getImagination(int i) {
//        return  imagination.get(i);
//    }

//    public ImageLabel getReality() {
//        return reality;
//    }

    public String outString() {
   //     assert(false);
//        float out[]=bp.output();
//        String ret="";
//        for (int i=0;i<layerSizes[layerSizes.length-1];i++){
//            ret+="|"+i+":"+String.format("%3.2f ",out[i]);
//        }
//        return ret;
        return "XX";
    }

    
    private void loadTraining(Data data) {
        System.arraycopy(data.image, 0, in, 0, nPixel);
        System.arraycopy(data.label, 0,in, nPixel, nLabel);
    }
  
    
    private void loadFire(Data data) {
        System.arraycopy(data.image, 0, in, 0, nPixel);
        Arrays.fill(in, nPixel, nPixel+nLabel,0.5f);
    }
  
    
    private synchronized void loadOut(Data data) {
        System.arraycopy(bp.output(), nPixel,result.out.label, 0, nLabel);
        System.arraycopy(bp.output(), 0,result.out.image, 0, nPixel);
        System.arraycopy(data.label, 0,result.in.label, 0, nLabel);
        System.arraycopy(data.image, 0,result.in.image, 0, nPixel);
    }
    
    /**
     * copy cached result into result supplied by caller
     * 
     * @param result   overwritten with current cached result
     */
    public synchronized void  getLatestResult(Result res) {
        if (this.result == null) return;
        
        System.arraycopy(this.result.in.label, 0,res.in.label, 0, nLabel);
        System.arraycopy(this.result.in.image, 0,res.in.image, 0, nPixel);
        
        System.arraycopy(this.result.out.label, 0,res.out.label, 0, nLabel);
        System.arraycopy(this.result.out.image, 0,res.out.image, 0, nPixel);
    
    }
    
    public void fire(Data data) {        
        loadFire(data);
        bp.ffwd(in);
        loadOut(data);
        setChanged();
    }

    public void setTrain(Data data) {
        loadTraining(data); 
        bp.bpgt(in,in);
 //       reality.setData(data);
        loadOut(data);
        setChanged();
    }

    public Vector<Tweakable> getTweaks() {
        return bp.getTweaks();
    }

    public void dump() {
        throw new UnsupportedOperationException("Not supported yet.");
    }



    
}
